//包含LUA的头文件，用来支持脚本
#include <stdio.h>
#include "lib/lua-5.3.1/lua.h"  
#include "lib/lua-5.3.1/lualib.h"  
#include "lib/lua-5.3.1/lauxlib.h"   

#include "lib/includes.h"

#define PICC_ADD                    0xC1            //加
#define PICC_SUB                    0xC0            //减
#define PICC_RESTORE                0xC2            //恢复

#define PICC_KEYA                   0x60            //KEY A
#define PICC_KEYB                   0x61            //KEY B

#define PICC_NULL                   0x00            //不校验KEY


lua_State* L;  

U08 gCardSN[8]; //物理卡号

U32 ICF_SelectAID( const char *AID, U32 ilen, U32 ich )
{
    U32 rcode;
    
    gCmdBuffer[0] = 0x00;   //CLA
    gCmdBuffer[1] = 0xA4;   //INS
    gCmdBuffer[2] = 0x04;   //P1
    gCmdBuffer[3] = 0x00;   //P2
    gCmdBuffer[4] = ilen;   //Lc
    CurCalc_DataCpy( gCmdBuffer+5, (U08*)AID, ilen );
    
    rcode = ICC_APDU_Exchange( ich, gCmdBuffer, ilen+5, gpRcvBuffer, &Grcv_Len, 260 );
    if( rcode != 0 )
    { return rcode; }
    
    if( Grcv_Len < 2 )  
    { return 2;}
    rcode = ( ( gpRcvBuffer[ Grcv_Len - 2 ] << 8 ) | gpRcvBuffer[ Grcv_Len - 1 ] );

    return rcode;

}
U32 ICF_SelectSFI( const char *SFI, U32 ich )
{
    U32 rcode;

    gCmdBuffer[0] = 0x00;   //CLA
    gCmdBuffer[1] = 0xA4;   //INS
    gCmdBuffer[2] = 0x00;   //P1
    gCmdBuffer[3] = 0x00;   //P2
    gCmdBuffer[4] = 0x02;   //Lc
    CurCalc_DataCpy( gCmdBuffer+5, (U08*)SFI, 2 );
    
    rcode = ICC_APDU_Exchange( ich, gCmdBuffer, 2+5, gpRcvBuffer, &Grcv_Len, 260 );
    if( rcode != 0 )
    { return rcode; }
    
    if( Grcv_Len < 2 )
    { return 2;}
    rcode = ( ( gpRcvBuffer[ Grcv_Len - 2 ] << 8 ) | gpRcvBuffer[ Grcv_Len - 1 ] );

    return rcode;
}
U32 ICF_ReadBinaryFile( U08 SFI, U08 Offset, U08 BytesToRead, U32 ich )
{
    unsigned short rcode;
    
    gCmdBuffer[0] = 0x00;   //CLA
    gCmdBuffer[1] = 0xB0;   //INS
    gCmdBuffer[2] = 0x80 | ( SFI & 0x1F );  //P1
    gCmdBuffer[3] = Offset; //P2
    gCmdBuffer[4] = BytesToRead;    //Le

    rcode = ICC_APDU_Exchange( ich, gCmdBuffer, 5, gpRcvBuffer, &Grcv_Len, 260 );
    if( rcode != 0 )
    { return rcode; }

    if( Grcv_Len < 2 )                                          //长度判断
    { return 2;}
    rcode = ( ( gpRcvBuffer[ Grcv_Len - 2 ] << 8 ) | gpRcvBuffer[ Grcv_Len - 1 ] );

    return rcode;
}

int LConnect(lua_State* L)
{
    int ret = 0;
    size_t le = 0;
    printf("Connecting...\n");
    const char * ipaddr = luaL_checklstring(L,1,&le);
    //printf("cmd is %s,le is %d\n",aid,le);  
    //从L栈中取出索引为2的数值，并检查  
    int port = luaL_checkinteger(L,2); 
    printf("ServerIP:%s,Port:%d\n", ipaddr,port);
    ret = Connect(ipaddr,port);
   
    lua_pushnumber(L,ret); 
    return 1;
}

int LDisConnect(lua_State* L)
{
    printf("Close connect!\n");
    Com_Dev_Disconnect( 0 );  
    return 1;
}

int LTxData(lua_State* L)
{
    int ret = 0;
    unsigned int len = 0;
    size_t le = 0;
    unsigned char buf[1024];
    unsigned char outbuf[2048];
    memset(buf, 0, 1024);
    memset(outbuf, 0, 2048);
    //从L栈中取出索引为1的数值，并检查  
    const char * txdata = luaL_checklstring(L,1,&le);
    //printf("tx is %s,le is %d\n",txdata,le);  
    StrToHex( (char*)txdata, le, buf );

    ret = Com_Dev_TxData( buf, le/2, 0, 0 );
	if( ret != 0 )
	{ DEF_SysCard_Debug; return ret; }
	
    ret = Com_Dev_RxData( buf, &len,  1024, 0, 0 ); 
	if( ret != 0 )
	{ DEF_SysCard_Debug; return ret; }

	HexToStr(buf,len,(char*)outbuf);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)outbuf,strlen((char*)outbuf));
    return 2;

}

int LTxData1(lua_State* L)
{
    int ret = 0;
    unsigned int len = 0;
    size_t le = 0;
    unsigned char buf[1024];
    unsigned char outbuf[2048];
    memset(buf, 0, 1024);
    memset(outbuf, 0, 2048);
    //从L栈中取出索引为1的数值，并检查  
    const char * txdata = luaL_checklstring(L,1,&le);
   // printf("tx is %s,le is %d\n",txdata,le);  
    //StrToHex( (char*)txdata, le, buf );

    ret = Com_Dev_TxData1( (unsigned char*)txdata, le, 0, 0 );
	if( ret != 0 )
	{ DEF_SysCard_Debug; return ret; }
	
    ret = Com_Dev_RxData1( buf, &len,  1024, 0, 0 ); 
	if( ret != 0 )
	{ DEF_SysCard_Debug; return ret; }

	//HexToStr(buf,len,(char*)outbuf);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)buf,len);
    return 2;

}
int LAPDU_Exchange(lua_State* L)
{
	int ret = 0;
 	size_t le = 0;
 	unsigned char buf[520];
	
	memset(buf, 0, 520);
 	//从L栈中取出索引为1的数值，并检查  
    const char * cmd = luaL_checklstring(L,1,&le);
    //printf("cmd is %s,le is %d\n",aid,le);  
    //从L栈中取出索引为2的数值，并检查  
    int ich = luaL_checkinteger(L,2); 

    StrToHex( (char*)cmd, le, gCmdBuffer );

    ret = ICC_APDU_Exchange( ich, gCmdBuffer, le/2, gpRcvBuffer, &Grcv_Len, 260 );
    if( Grcv_Len < 2)
	{ return 1;}

    ret = ( ( gpRcvBuffer[ Grcv_Len - 2 ] << 8 ) | gpRcvBuffer[ Grcv_Len - 1 ] );

    HexToStr(gpRcvBuffer,Grcv_Len,(char*)buf);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)buf,strlen((char*)buf));
    return 2;
}
int LSelectAID(lua_State* L)
{
    int ret = 0;
    size_t le = 0;
    unsigned char buf[520];
    
    memset(buf, 0, 520);
    //从L栈中取出索引为1的数值，并检查  
    const char * aid = luaL_checklstring(L,1,&le);
    //printf("aid is %s,le is %d\n",aid,le);  
    //从L栈中取出索引为2的数值，并检查  
    int len = luaL_checkinteger(L,2); 
    int ich = luaL_checkinteger(L,3); 

    ret = ICF_SelectAID( aid, len, ich );
    HexToStr(gpRcvBuffer,Grcv_Len,(char*)buf);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)buf,strlen((char*)buf));
    return 2;

}

int LSelectSFI(lua_State* L)
{
    int ret = 0;
    size_t le = 0;
    unsigned char buf[520];
    
    memset(buf, 0, 520);
    //从L栈中取出索引为1的数值，并检查  
    const char * sfi = luaL_checklstring(L,1,&le);
    //printf("aid is %s,le is %d\n",aid,le);  
    //从L栈中取出索引为2的数值，并检查  
    int ich = luaL_checkinteger(L,2); 

    ret = ICF_SelectSFI( sfi, ich );
    HexToStr(gpRcvBuffer,Grcv_Len,(char*)buf);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)buf,strlen((char*)buf));
    return 2;

}
int LReadBinaryFile( lua_State* L )
{
    int ret = 0;
    unsigned char buf[520];
    
    memset(buf, 0, 520);
    //从L栈中取出索引为1的数值，并检查  
    int sfi =  luaL_checkinteger(L,1); 
    int oft =  luaL_checkinteger(L,2);
    int rlen = luaL_checkinteger(L,3);
    int ich =  luaL_checkinteger(L,4); 

    ret = ICF_ReadBinaryFile(sfi,oft,rlen,ich);

    HexToStr(gpRcvBuffer,Grcv_Len,(char*)buf);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)buf,strlen((char*)buf));

    //stackDump(L);
    return 2;
}
//获取CPU或M1卡的物理卡号
int LGetPhySn( lua_State* L )
{
    int ret = 0;
    unsigned char buf[20];
    unsigned char buf1[20];

    memset(buf,0,20);
    memset(buf1,0,20);

    ret = ICC_MiOne_GetPhySn(buf);

    memcpy(gCardSN,buf,8);//保存全局物理卡号

    HexToStr(buf,8,(char*)buf1);
    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)buf1,strlen((char*)buf1));
    //stackDump(L);
    return 2;
}
//M1卡扇区读
int LBlkRead( lua_State* L )
{
    int ret = 0;
    size_t le = 0;
    unsigned char rbuf[50];
    unsigned char sbuf[50];
    unsigned char key[16];
    unsigned char cmd=0;

    int block   =  luaL_checkinteger(L,1); 
    const char * keys = luaL_checklstring(L,2,&le);
    int keytype =  luaL_checkinteger(L,3); //密码类型,0,不校验 1,A码，2，B码

    memset(rbuf,0,50);
    memset(sbuf,0,50);
    StrToHex( (char*)keys, le, key );

    cmd = PICC_KEYA;
    if(keytype == 1)
    { cmd = PICC_KEYA; }
    else if(keytype == 2)
    { cmd = PICC_KEYB; }

    ret = ICC_MiOne_BlkRead(block,cmd,key, gCardSN, rbuf );

    HexToStr(rbuf,16,(char*)sbuf);

    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)sbuf,strlen((char*)sbuf));
    //stackDump(L);
    return 2;
}

//M1卡扇区写
int LBlkWrite( lua_State* L )
{
    int ret = 0;
    size_t le = 0,le1 =0;
    unsigned char wbuf[50];
    unsigned char key[16];
    unsigned char cmd=0;

    int block   =  luaL_checkinteger(L,1); 
    const char * wbufs = luaL_checklstring(L,2,&le);
    const char * keys = luaL_checklstring(L,3,&le1);
    int keytype =  luaL_checkinteger(L,4); //密码类型,0,不校验 1,A码，2，B码

    memset(wbuf,0,50);

    StrToHex( (char*)wbufs, le, wbuf );
    StrToHex( (char*)keys, le1, key );

    cmd = PICC_KEYA;
    if(keytype == 1)
    { cmd = PICC_KEYA; }
    else if(keytype == 2)
    { cmd = PICC_KEYB; }

    ret = ICC_MiOne_BlkWrite(block,cmd,key, gCardSN, wbuf );

    lua_pushinteger(L,ret); 
    //stackDump(L);
    return 1;
}

//DES加密
int LDES_Encrypt( lua_State* L )
{
   // int ret = 0;
    size_t le = 0,le1 =0;
    unsigned char inkey[16];
    unsigned char indata[16];
    unsigned char outdata[16];
	unsigned char str_out[50];
    const char * str_inkey = luaL_checklstring(L,1,&le);
    const char * str_indata = luaL_checklstring(L,2,&le1);

    StrToHex( (char*)str_inkey, le, inkey );
    StrToHex( (char*)str_indata, le1, indata );

	CurCalc_DES_Encrypt( inkey, indata, outdata );
	
	HexToStr(outdata,8,(char*)str_out);

    //lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)str_out,16);
    //stackDump(L);
    return 1;
}

//DES解密
int LDES_Decrypt( lua_State* L )
{
   // int ret = 0;
    size_t le = 0,le1 =0;
    unsigned char inkey[16];
    unsigned char indata[16];
    unsigned char outdata[16];
	unsigned char str_out[50];
    const char * str_inkey = luaL_checklstring(L,1,&le);
    const char * str_indata = luaL_checklstring(L,2,&le1);

    StrToHex( (char*)str_inkey, le, inkey );
    StrToHex( (char*)str_indata, le1, indata );

	CurCalc_DES_Decrypt( inkey, indata, outdata );
	
	HexToStr(outdata,8,(char*)str_out);

    //lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)str_out,16);
    //stackDump(L);
    return 1;
}


//3DES加密
int LDES_3Encrypt( lua_State* L )
{
   // int ret = 0;
    size_t le = 0,le1 =0;
    unsigned char inkey[16];
    unsigned char indata[16];
    unsigned char outdata[16];
	unsigned char str_out[50];
    const char * str_inkey = luaL_checklstring(L,1,&le);
    const char * str_indata = luaL_checklstring(L,2,&le1);

    StrToHex( (char*)str_inkey, le, inkey );
    StrToHex( (char*)str_indata, le1, indata );

	CurCalc_3DES_Encrypt( inkey, indata, outdata );
	
	HexToStr(outdata,16,(char*)str_out);

    //lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)str_out,32);
    //stackDump(L);
    return 1;
}

//3DES解密
int LDES_3Decrypt( lua_State* L )
{
   // int ret = 0;
    size_t le = 0,le1 =0;
    unsigned char inkey[16];
    unsigned char indata[16];
    unsigned char outdata[16];
	unsigned char str_out[50];
    const char * str_inkey = luaL_checklstring(L,1,&le);
    const char * str_indata = luaL_checklstring(L,2,&le1);

    StrToHex( (char*)str_inkey, le, inkey );
    StrToHex( (char*)str_indata, le1, indata );

	CurCalc_3DES_Decrypt( inkey, indata, outdata );
	
	HexToStr(outdata,16,(char*)str_out);

    //lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)str_out,32);
    //stackDump(L);
    return 1;
}


U32 MathDesMac( U08 *pbuf, U32 length, U08 *key,U08 checktype )
{
	U32 len ;
	U08 mac[8], mac1[8];

	len = length ;

	if( checktype == 0 )
	{
		CurCalc_DES_MAC64( (SINGLE_DES_ENCRYPTION|ZERO_CBC_IV), key, 0, pbuf, len ,  mac );
		memcpy( pbuf+len, mac, 8 );
		return 0 ;
	}
	else
	{
		//暂存源校验码
		memcpy( mac1, pbuf+len-8, 8 ) ; 
		CurCalc_DES_MAC64( (SINGLE_DES_ENCRYPTION|ZERO_CBC_IV), key, 0, pbuf, len-8 ,  mac) ; 

		if ( memcmp( mac, mac1, 8 ) == 0x00 )
		{
			return 0 ;	 	//校验产生的校验码和原校验码相等, 校验成功
		}
		else
		{
			return 1 ;	  	//校验产生的校验码和原校验码不等, 校验失败
		}
	}	
}

int LMathDesMac( lua_State* L )
{
    int ret = 0;
    size_t le = 0,le1 =0;
    unsigned char inkey[16];
    unsigned char indata[1024];
	unsigned char str_out[2048];
    
    const char * str_indata = luaL_checklstring(L,1,&le);
	int   inlen   =  luaL_checkinteger(L,2);
	const char * str_inkey = luaL_checklstring(L,3,&le1);
	int   type   =   luaL_checkinteger(L,4);
    StrToHex( (char*)str_indata, le, indata );
	StrToHex( (char*)str_inkey, le1, inkey );

	ret = MathDesMac( indata, inlen,inkey,type );
	
	memset(str_out,0,2048);
	HexToStr(indata,inlen+8,(char*)str_out);

    lua_pushinteger(L,ret); 
    lua_pushlstring(L,(char*)str_out,strlen((char*)str_out));
    //stackDump(L);
    return 1;
}
int main( void )  
{  
    //初始化全局L  
    L = luaL_newstate();  //创建lua的栈 
    //打开库  
    luaL_openlibs(L);  
    //把函数压入栈中  
    //lua_pushcfunction(L, add);  
    //设置全局ADD  
    //lua_setglobal(L, "ADD");  
    //lua_register(L,"ADD",add);
    lua_pushcfunction(L, LConnect);  
    //设置全局ADD  
    lua_setglobal(L, "CONNECT"); 
    
    lua_register(L,"DISCONNECT", LDisConnect); 

    lua_register(L,"TxData",LTxData);
	lua_register(L,"TxData1",LTxData1);
	
    lua_register(L,"APDU", LAPDU_Exchange);  

    lua_register(L,"S_AID",LSelectAID); 
    lua_register(L,"S_SFI",LSelectSFI); 
    lua_register(L,"R_BFile",LReadBinaryFile);
    
    lua_register(L,"G_SN",LGetPhySn);
    lua_register(L,"R_Block",LBlkRead);
    lua_register(L,"W_Block",LBlkWrite);
	
	lua_register(L,"DES_Enc",LDES_Encrypt);
    lua_register(L,"DES_Dec",LDES_Decrypt);
	
	lua_register(L,"DES_3Enc",LDES_3Encrypt);
    lua_register(L,"DES_3Dec",LDES_3Decrypt);
	
	lua_register(L,"MathDesMac",LMathDesMac);
	
    //加载我们的lua脚本文件  
    if(luaL_loadfile(L,"test.lua"))  //载入lua脚本，是通过fopen打开的，
    {  
        printf("error,failed to analysis script!\nmaybe syntax error!\n");  
    }  
    //安全检查  
    lua_pcall(L,0,0,0); //这个函数会执行lua脚本 
    //push进lua函数  
   // lua_getglobal(L, "mylua1"); 
   // lua_pcall(L,0,0,0);   
    printf("end my lua script,finish!\n"); 
    lua_close(L); //关闭lua的栈  

    return 0;  
}  